#pragma once

#include "data_type.hpp"

#pragma pack(1)

// 心跳消息(TypeID=0x00)
struct MDQPHeader
{
    uint8_t flag_low : 4;  // 协议版本号，当前版本号为 1
    uint8_t flag_high : 4; // 高4位中的最低位(即第4位,Flag&0x10)为消息结束标识位。 消息标识位为0时表示当前报文为本消息最后一个报文， 为1时表示后续报文仍然为同一个消息的报文。其余3位标识位尚未使用。
    int8_t type_id;        // 报文类型，
    uint16_t length;       // 报文体长度
    int32_t request_id;    // 用户请求编号。MDQP协议中，用户进行查询请求时， 需提供一个请求编号来唯一标识其发起的某一个请求。
};

// 每个MDQP报文都有一个报文体，一个报文体有多个域
// 对于响应报文，第一个域ResponseFiledResponse
// 如果该报文是心跳报文的话，那么该报文的报文体是空的，length为0
// request_id 无意义, 报文头的type_id 为 0x00


// filed_id=0x0001
struct ResponseFiledResponse
{
    int32_t error_id;   // 错误代码,0表示成功
    char error_msg[81]; // 错误信息
};

/////////////////////////下面是应用的结构体///////////////////////////

// 登录消息的报文体只有一个域，即LoginRequest
// 登录消息(TypeID=0x11, filed_id = 0x0002)
struct LoginRequest
{
    char user_id[16];                // 交易用户代码
    char participant_id[11];         // 会员代码
    char password[41];               // 密码
    char language;                   // 语言。影响错误信息等字段的解码语言。取值范围: '0': 中文(GB18030), '1': 英文
    char user_product_info[41];      // 用户端产品信息。用以指明用户端使用何种行情客户端
    char interface_product_info[41]; // 接口端产品信息。在用户使用不同厂商提供的协议解码软件和行情客户端软件时，用以指明用户端使用何种协议解码软件
};

/////////////////////////登录应答/////////////////////////

//////////////(响应信息域)(登录应答域)^{<=1}

// typeid=0x12, filed_id=0x0003
struct LoginResponse
{
    char trading_day[9];          // 交易日，格式为"YYYYMMDD\0"
    char login_time[9];           // 登录成功时间，格式为"hh:mm:ss\0"
    char user_id[16];             // 交易用户代码
    char participant_id[11];      // 会员代码
    char trading_system_name[61]; // 系统名称
    char action_day[9];           // 自然日，格式与交易日同
};

// 登出消息(TypeID=0x13) filed_id = 0x0004
struct LogOutRequest
{
    char user_id[16];        // 交易用户代码
    char participant_id[11]; // 会员代码
};

// 响应报文体 (响应信息域)(登出应答域)<=1
// 登出应答(TypeID=0x14) filed_id = 0x0005
struct LogOutResponse
{
    char user_id[16];        // 交易用户代码
    char participant_id[11]; // 会员代码
};

/////////////////////////////////////主题行情快照查询功能/////////////////////////////////////

// 快照查询请求 (TypeID=0x31) filed_id = 0x1001
struct SnapshotRequest
{
    int16_t topic_id; // 主题代码
    int32_t snap_no;  // 快照编号,-1表示最新快照
};

// 快照查询应答 (TypeID=0x32)
// 中心切换历史域 filed_id = 0x0032
struct CenterSwitchHistoryResponse
{
    int8_t center_change_no; // 数据中心切换编号
    int32_t snap_no;         // 快照编号
    int32_t packet_no;       // 本次数据中心切换时的增量行情报文编号
};

// 结算会话域, filed_id = 0x0031
struct SettlementSessionResponse
{
    char trading_day[9];         // 交易日。格式 "YYYYMMDD\0"
    char settlement_gruop_id[9]; // 结算组代码
    int32_t settlement_id;       // 结算编号
};

// 快照标识域与查询请求中的快照标识域相同
typedef SnapshotRequest SnapshotResponse;

// 主题属性域 filed_id = 0x1003
struct MarketAttributeResponse
{
    int32_t market_data_depth; // 主题行情深度
    char cipher_algorithm;     // 加密算法 '0' 不加密
    uint8_t cipher_key[16];    // 密钥，仅在加密算法不为 '0' 时有效
    uint8_t cipher_iv[16];     // 加密初始化矢量，仅在加密算法不为 '0' 时有效
};

// 快照时间域 filed_id = 0x1002
struct SnapshotTimeResponse
{
    char snap_date[9];     // 采样日期，格式为 "YYYYMMDD\0"
    char snap_time[9];     // 采样时间（到秒级），格式为 "hh:mm:ss\0"
    int32_t snap_millisec; // 毫秒级采样时间
};

// 增量行情报文编号域 filed_id = 0x1004
struct IncrementalMarketDataPacketNoResponse
{
    int32_t packet_no; // 增量行情报文最新编号
};

// 合约信息域 filed_id = 0x0101
struct InstrumentInfoResponse
{
    char instrument_id[31];       // 合约代码，合约的唯一标识字符串
    char underlying_instr_id[31]; // 基础商品代码
    char product_class;           // 合约所属的产品类型，即合约类型
    Double strike_price;          // 执行价，期权合约专用
    char options_type;            // 期权类型，期权合约专用
    int32_t volume_multiple;      // 合约数量乘数，标明每手该合约包含多少单位的标的物
    Double underlying_multiple;   // 合约基础商品乘数
    int32_t is_trading;           // 标明是否交易，0表示非交易，其他为交易状态
    char currency_id[4];          // 合约的币种代码，目前支持“CNY”和空值，“CNY”表示人民币；空值用于指数合约
    Double price_tick;            // 最小变动价位，合约价格必须是最小变动价位的整数倍
    Double codec_price;           // 编码基准价，特殊信息，由平台指定，一般为昨结算价，用作增量行情中一些价格字段的编解码基准
    int32_t instrument_no;        // 合约编码，唯一对应一个合约代码，将合约代码映射到 32 位整型编码中以减少编码字节数
};

// 成交行情域 filed_id=0x0102
struct InstrumentTradingInfoResponse
{
    int32_t instrument_no;       // 合约编码，与合约信息域中的合约编码对应
    Double last_price;           // 最新价
    int32_t volume;              // 合约数量，统计本交易日已经成交的合约手数
    Double turnover;             // 成交金额，统计本交易日该合约的成交金额总和
    Double open_interest;        // 持仓量，统计该合约目前在市场中的总持仓
    Double highest_price;        // 最高价，统计本交易日到目前为止的最高成交价
    Double lowest_price;         // 最低价，统计本交易日到目前为止的最低成交价
    Double open_price;           // 今开盘
    Double close_price;          // 今收盘
    Double settlement_price;     // 今结算
    Double upper_limit_price;    // 涨停板价
    Double lower_limit_price;    // 跌停板价
    Double pre_settlement_price; // 昨结算
    Double pre_close_price;      // 昨收盘
    Double pre_open_interest;    // 昨持仓量，本交易日开盘前的该合约总持仓
    Double pre_delta;            // 昨虚实度
    Double curr_delta;           // 今虚实度
    char action_day[9];          // 业务发生日期
    char update_time[9];         // 最近修改秒级时间
    int32_t update_milli_sec;    // 最近修改毫秒级时间
    int32_t change_no;           // 当前合约行情快照编号
};

// 分价表域 filed_id = 0x0103
struct InstrumentPriceLevelResponse
{
    int32_t instrument_no; // 合约编码，与合约信息域中的合约编码对应
    char direction;        // '0' 买，'1' 卖
    Double price;          // 价格档位
    int32_t volume;        // 档位对应的数量
};

// 报单统计信息域 filed_id = 0xx0104
struct InstrumentOrderStatResponse
{
    int32_t instrument_no; // 合约编码，与合约信息域中的合约编码对应
    int32_t bid_volume;    // 买报单总量，统计当前买方向所有报单的合约手数之和
    Double bid_amount;     // 买报单总金额，买方向所有报单的金额总和，计算公式为：∑(买方向)((报单价) * (报单量) * (合约乘数))
    int32_t ask_volume;    // 卖报单总量，统计当前卖方向所有报单的合约手数之和
    Double ask_amount;     // 卖报单总金额，卖方向所有报单的金额总和，计算公式为：∑(卖方向)((报单价) * (报单量) * (合约乘数))
};

// 增量查询请求 (TypeID=0x33) filed_id = 0x0201
struct IncrementalLookUpRequest
{
    int16_t topic_id;        // 主题代码
    int32_t start_packet_no; // 开始报文编号（包含）
    int32_t end_packet_no;   // 结束报文编号（不包含）
};

// 增量查询应答 (TypeID=0x34)
// 增量查询应答消息以通用域的形式传输增量行情报文，每个通用域中包含一个增量行情报文。
// 通用域(FieldID=0x0000)的域体为未定义的二进制数据。
// 通用域是通用的，可用来发送任意数据。但MDQP协议不能 
// 对通用域域体进行解码，一般需要额外指定解析算法。
// 例如，增量行情报文需要用MIRP协议进行解码。
struct IncrementalLookUpResponse{

};

#pragma pack()
